package com.cleaningcloud.cld.service.impl;

import com.cleaningcloud.cld.domain.*;
import com.cleaningcloud.cld.domain.dto.CldAssetsRecordDto;
import com.cleaningcloud.cld.domain.dto.CldMaterialAllocateDto;
import com.cleaningcloud.cld.domain.dto.CldProjectPostDto;
import com.cleaningcloud.cld.domain.dto.ClockInDto;
import com.cleaningcloud.cld.domain.vo.*;
import com.cleaningcloud.cld.mapper.*;
import com.cleaningcloud.cld.mapper.other.WarehouseInventoryMapper;
import com.cleaningcloud.cld.service.ICldAssetsRecordService;
import com.cleaningcloud.cld.service.ICldMaterialAllocateService;
import com.cleaningcloud.cld.service.ICldProjectService;
import com.cleaningcloud.common.core.constant.SecurityConstants;
import com.cleaningcloud.common.core.utils.DateUtils;
import com.cleaningcloud.common.core.utils.UniqueIdUtils;
import com.cleaningcloud.common.security.utils.SecurityUtils;
import com.cleaningcloud.erp.api.RemoteWareService;
import io.seata.spring.annotation.GlobalTransactional;
import net.sourceforge.pinyin4j.PinyinHelper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;

/**
 * 项目Service业务层处理
 *
 * @author cleaningcloud
 * @date 2024-10-02
 */
@Service
public class CldProjectServiceImpl implements ICldProjectService {
    @Autowired
    private CldProjectMapper cldProjectMapper;

    @Autowired
    private CldContractMapper cldContractMapper;

    @Autowired
    private CldProjectPostMapper cldProjectPostMapper;

    @Autowired
    private ICldAssetsRecordService cldAssetsRecordService;

    @Autowired
    private WarehouseInventoryMapper warehouseInventoryMapper;

    @Autowired
    private ICldMaterialAllocateService cldMaterialAllocateService;

    @Autowired
    private CldStaffContractMapper cldStaffContractMapper;

    @Autowired
    private RemoteWareService remoteWareService;

    @Autowired
    private CldStaffMapper cldStaffMapper;

    @Autowired
    private CldProjectAccountMapper cldProjectAccountMapper;

    @Autowired
    private CldInvoiceMapper cldInvoiceMapper;

    @Autowired
    private CldSettlementMapper cldSettlementMapper;


    /**
     * 将中文转换为拼音并获取首字母
     *
     * @param chinese 中文字符串
     * @return 拼音字符串
     */
    public static String convertChineseToPinyin(String chinese) {
        StringBuilder pinyin = new StringBuilder();
        for (char c : chinese.toCharArray()) {
            String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c);
            if (pinyinArray != null && pinyinArray.length > 0) {
                pinyin.append(pinyinArray[0].charAt(0));
            } else {
                pinyin.append(c);
            }
        }
        return pinyin.toString().toUpperCase();
    }

    /**
     * 查询项目
     *
     * @param projectId 项目主键
     * @return 项目
     */
    @Override
    public CldProject selectCldProjectByProjectId(Long projectId) {
        return cldProjectMapper.selectCldProjectByProjectId(projectId);
    }

    @Override
    public List<CldProject> getList(CldProject cldProject) {
        return cldProjectMapper.getList(cldProject);
    }

    /**
     * 查询项目列表
     *
     * @param cldProject 项目
     * @return 项目
     */
    @Override
    public List<CldProjectVo> selectCldProjectList(CldProject cldProject) {
        return cldProjectMapper.selectCldProjectList(cldProject);
    }

    @Override
    public List<CldProjectContractVo> selectCldProjectContractList(CldProject cldProject) {

        return cldProjectMapper.selectCldProjectContractList(cldProject);
    }

    /**
     * 新增项目
     *
     * @param cldProject 项目
     * @return 结果
     */
    @Override
    public int insertCldProject(CldProject cldProject) {
        cldProject.setCreateTime(DateUtils.getNowDate());
        cldProject.setUpdateTime(cldProject.getCreateTime());
        cldProject.setCreateId(SecurityUtils.getUserId());
        cldProject.setUpdateBy(String.valueOf(SecurityUtils.getUsername()));
        cldProject.setCreateName(SecurityUtils.getUsername());
        cldProject.setProjectStatus(1L);//项目线索 (1线索2签订)
        cldProject.setFlag(0L);
        // 项目编号 ---- 按照项目名称缩写例如：株洲(ZZ)-区域(QY)-项目名(XMM)
        String projectNo = convertChineseToPinyin(cldProject.getCity().replace("市", ""))
                + "-QY"
                + "-" + convertChineseToPinyin(cldProject.getProjectName());

        cldProject.setProjectNo(projectNo);
        return cldProjectMapper.insertCldProject(cldProject);
    }

    /**
     * 修改项目
     *
     * @param cldProject 项目
     * @return 结果
     */
    @Override
    public int updateCldProject(CldProject cldProject) {
        return cldProjectMapper.updateCldProject(cldProject);
    }

    /**
     * 批量删除项目
     *
     * @param projectIds 需要删除的项目主键
     * @return 结果
     */
    @Override
    public int deleteCldProjectByProjectIds(Long[] projectIds) {
        return cldProjectMapper.deleteCldProjectByProjectIds(projectIds);
    }

    /**
     * 删除项目信息
     *
     * @param projectId 项目主键
     * @return 结果
     */
    @Override
    public int deleteCldProjectByProjectId(Long projectId) {
        return cldProjectMapper.deleteCldProjectByProjectId(projectId);
    }

    @Override
    @Transactional
    public int clockIn(ClockInDto clockInDto) {
        CldProject cldProject = cldProjectMapper.selectCldProjectByProjectId(clockInDto.getProjectId());
        if (cldProject == null) {
            throw new RuntimeException("项目数据不存在！");
        }
        CldProject cldProjectNew = new CldProject();
        cldProjectNew.setRange(clockInDto.getRange());
        cldProjectNew.setLatitude(clockInDto.getLatitude());
        cldProjectNew.setLongitude(clockInDto.getLongitude());
        cldProjectNew.setUpdateTime(DateUtils.getNowDate());
        cldProjectNew.setUpdateBy(SecurityUtils.getUsername());
        cldProjectNew.setProjectId(cldProject.getProjectId());
        cldProjectMapper.updateCldProject(cldProjectNew);
        return 1;
    }

    @Override
    public int projectContractExpires(Long projectId) {
        CldProject cldProject = cldProjectMapper.selectCldProjectByProjectId(projectId);
        if (cldProject == null) {
            throw new RuntimeException("项目数据不存在！");
        }
        // 项目信息设为终止
        cldProject.setProjectStatus(3L);
        cldProjectMapper.updateCldProject(cldProject);
        // 查询合同信息
        CldContract contract = cldContractMapper.selectCldContractByProjectId(cldProject.getProjectId());
        if (contract == null) {
            throw new RuntimeException("项目合同信息不存在！");
        }
        // 查询项目小组人员
        CldProjectPostDto postQuery = new CldProjectPostDto();
        postQuery.setProjectId(cldProject.getProjectId());
        postQuery.setIsMasterDuits(1L);
        List<CldProjectPostSetVo> postList = cldProjectPostMapper.selectCldProjectPostList(postQuery);
        List<Long> staffIds = new ArrayList<>();
        if (!postList.isEmpty()) {
            for (CldProjectPostSetVo projectPostSetVo : postList) {
                staffIds.add(projectPostSetVo.getStaffId());
            }
            cldStaffMapper.batchUpdateStaffStatus(staffIds);
        }
        // 设置合同状态为终止
        contract.setContractStatus(2L);
        // 客户账号设为删除状态
        cldProjectAccountMapper.batchDeleteByProjectId(cldProject.getProjectId());
        // 在岗人员解绑
        cldProjectPostMapper.allUnbindingJobByProjectId(cldProject.getProjectId());
        // 合同信息变更为无效
        cldStaffContractMapper.allUnbindingContractByProjectId(3, cldProject.getProjectId());
        // 资产信息解绑
        assetsRecordUnbinding(cldProject.getProjectId());
        // 物资调回临时仓
        materialAllocation(cldProject.getProjectId());
        // 项目仓库 岗位仓库设为无效
        remoteWareService.closureWareHouse(cldProject.getProjectId(), SecurityConstants.INNER);

        // 生成最后一个月发票记录 签订日期不为1号
        // 获取合同签订日期
        LocalDate cDay = contract.getStartDate().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
        if(cDay.getDayOfMonth() != 1){
            LocalDate currDate = LocalDate.now();
            // 根据签订日期 和当前日期计算相差天数
            BigDecimal invoiceAmount = contract.getContractMoney().divide(BigDecimal.valueOf(currDate.lengthOfMonth()), RoundingMode.CEILING).multiply(BigDecimal.valueOf(currDate.getDayOfMonth()));
            CldInvoice cldInvoice = new CldInvoice();
            cldInvoice.setProjectId(contract.getProjectId());
            cldInvoice.setServiceDate(DateUtils.getNowDate());
            // 应开票金额 合同金额÷合同总月份=每月应开票金额
            cldInvoice.setAnswerInvoiceAmount(invoiceAmount);
            cldInvoice.setInvoiceYear(currDate.getYear());
            cldInvoice.setInvoiceMonth(currDate.getMonthValue());
            cldInvoice.setInvoiceStatus(0L);
            cldInvoice.setSignStatus(0L);
            cldInvoice.setFlag(0L);
            cldInvoice.setCreateTime(DateUtils.getNowDate());
            cldInvoiceMapper.insertCldInvoice(cldInvoice);
            // 同时生成结算信息
            CldSettlement cldSettlement = new CldSettlement();
            cldSettlement.setInvoiceId(cldInvoice.getInvoiceId());
            cldSettlement.setCollectionStatus(0L);
            // 获取合同结算日
            cldSettlement.setSettlementDate(DateUtils.toDate(DateUtils.getNextDayToday(Math.toIntExact(contract.getSettlementDay()))));
            cldInvoice.setCreateTime(DateUtils.getNowDate());
            cldSettlementMapper.insertCldSettlement(cldSettlement);
        }

        return cldContractMapper.updateCldContract(contract);
    }

    @Override
    @Transactional
    @GlobalTransactional(rollbackFor = Exception.class)
    public int termination(CldContract cldContract) {
        CldProject cldProject = cldProjectMapper.selectCldProjectByProjectId(cldContract.getProjectId());
        if (cldProject == null) {
            throw new RuntimeException("项目数据不存在！");
        }

        CldProject cldProjectNew = new CldProject();
        cldProjectNew.setProjectId(cldProject.getProjectId());
        // 项目信息设为终止
        cldProjectNew.setProjectStatus(3L);
        cldProjectMapper.updateCldProject(cldProjectNew);
        // 查询合同信息
        CldContract contract = cldContractMapper.selectCldContractByProjectId(cldProject.getProjectId());
        if (contract == null) {
            throw new RuntimeException("项目合同信息不存在！");
        }
        // 查询项目小组人员
        CldProjectPostDto postQuery = new CldProjectPostDto();
        postQuery.setProjectId(cldProject.getProjectId());
        postQuery.setIsMasterDuits(1L);
        List<CldProjectPostSetVo> postList = cldProjectPostMapper.selectCldProjectPostList(postQuery);
        List<Long> staffIds = new ArrayList<>();
        if (!postList.isEmpty()) {
            for (CldProjectPostSetVo projectPostSetVo : postList) {
                staffIds.add(projectPostSetVo.getStaffId());
            }
            cldStaffMapper.batchUpdateStaffStatus(staffIds);
        }
        // 设置合同状态为终止
        contract.setContractStatus(3L);
        contract.setContractAttrs(cldContract.getContractAttrs());
        contract.setContractEndReason(cldContract.getContractEndReason());
        contract.setContractEndTime(cldContract.getContractEndTime());
        // 客户账号设为删除状态
        cldProjectAccountMapper.batchDeleteByProjectId(cldProject.getProjectId());
        // 在岗人员解绑
        cldProjectPostMapper.allUnbindingJobByProjectId(cldProject.getProjectId());
        // 合同信息变更为无效
        cldStaffContractMapper.allUnbindingContractByProjectId(3, cldProject.getProjectId());
        // 资产信息解绑
        assetsRecordUnbinding(cldProject.getProjectId());
        // 物资调回临时仓
        materialAllocation(cldProject.getProjectId());
        // 项目仓库 岗位仓库设为无效
        remoteWareService.closureWareHouse(cldProject.getProjectId(), SecurityConstants.INNER);
        return cldContractMapper.updateCldContract(contract);
    }

    @Override
    @Transactional
    public int projectRenewal(Long projectId) {
        CldProject cldProject = cldProjectMapper.selectCldProjectByProjectId(projectId);
        if (cldProject == null) {
            throw new RuntimeException("项目数据不存在！");
        }
        // 查询合同信息
        CldContract beforeContract = cldContractMapper.selectCldContractByProjectId(cldProject.getProjectId());
        if (beforeContract == null) {
            throw new RuntimeException("合同信息不存在！");
        }
        CldContract afterContract = new CldContract();
        BeanUtils.copyProperties(beforeContract, afterContract);
        // 修改之前合同信息为终止
        beforeContract.setContractStatus(3L);
        // 批量修改项目在岗人员人事合同状态
        cldStaffContractMapper.allUnbindingContractByProjectId(2, cldProject.getProjectId());
        cldContractMapper.updateCldContract(beforeContract);
        // 新增合同信息
        afterContract.setStartDate(DateUtils.getNowDate());
        afterContract.setSignDate(afterContract.getStartDate());
        afterContract.setEndDate(DateUtils.toDate(DateUtils.getNextYearToday()));
        afterContract.setContractId(null);
        cldContractMapper.insertCldContract(afterContract);
        // 新增人事合同信息
        CldProjectPostDto postQuery = new CldProjectPostDto();
        postQuery.setProjectId(projectId);
        postQuery.setIsMasterDuits(1L);
        List<CldProjectPostSetVo> postList = cldProjectPostMapper.selectCldProjectPostList(postQuery);
        List<CldStaffContract> contractList = new ArrayList<>();
        for (CldProjectPostSetVo projectPostSetVo : postList) {
            CldStaffContract cldStaffContract = new CldStaffContract();
            cldStaffContract.setProjectId(projectId);
            cldStaffContract.setStaffId(projectPostSetVo.getStaffId());
            cldStaffContract.setStaffContractNo(UniqueIdUtils.generateUniqueId());
            cldStaffContract.setStaffContratName(cldProject.getProjectName() + "-" + projectPostSetVo.getStaffName());
            cldStaffContract.setStartTime(afterContract.getStartDate());
            cldStaffContract.setEndTime(afterContract.getEndDate());
            cldStaffContract.setContractStatus(1L);
            cldStaffContract.setContractFile(2L);
            cldStaffContract.setFlag(0L);
            cldStaffContract.setCreateId(SecurityUtils.getUserId());
            cldStaffContract.setCreateName(SecurityUtils.getUsername());
            cldStaffContract.setCreateTime(DateUtils.getNowDate());
            contractList.add(cldStaffContract);
        }
        if (!contractList.isEmpty()) {
            cldStaffContractMapper.batchInsertCldStaffContract(contractList);
        }
        return 1;
    }


    /**
     * 资产信息解绑
     *
     * @param projectId
     */
    public void assetsRecordUnbinding(Long projectId) {
        // 项目资产  查询投放中的资产信息 资产信息解绑变更为闲置中
        CldAssetsRecordDto query = new CldAssetsRecordDto();
        query.setProjectId(projectId);
        query.setIsNewUpdate(1L);
        query.setRecordStatus(2L);
        List<CldAssetsRecordVo> list = cldAssetsRecordService.selectCldAssetsRecordList(query);
        for (CldAssetsRecordVo cldAssetsRecordVo : list) {
            cldAssetsRecordVo.setRecordStatus(1L);
            CldAssetsRecordDto cldAssetsRecordDto = new CldAssetsRecordDto();
            BeanUtils.copyProperties(cldAssetsRecordVo, cldAssetsRecordDto);
            cldAssetsRecordService.insertCldAssetsRecord(cldAssetsRecordDto);
        }
    }


    /**
     * 项目物资信息撤回临时仓
     *
     * @param projectId
     */
    public void materialAllocation(Long projectId) {
        // 查询项目仓及岗位仓下库存数量
        List<WarehouseInventoryVo> list = warehouseInventoryMapper.selectWarehouseInventoryListByProjectId(projectId);
        for (WarehouseInventoryVo warehouseInventoryVo : list) {
            CldMaterialAllocateDto cldMaterialAllocateDto = new CldMaterialAllocateDto();
            cldMaterialAllocateDto.setAllocateType(2L);
            // 默认临时仓
            cldMaterialAllocateDto.setMaterialInId(8L);
            cldMaterialAllocateDto.setMaterialOutId(warehouseInventoryVo.getWareId());
            cldMaterialAllocateDto.setDetailsList(warehouseInventoryVo.getDetailsList());
            cldMaterialAllocateDto.setIsConfirm(1L);
            cldMaterialAllocateDto.setRemark("项目终止,物资调回临时仓");
            cldMaterialAllocateService.insertCldMaterialAllocate(cldMaterialAllocateDto);
        }
    }
}
